
/**
 * AppleIIGo
 * Timing Generator class
 * (C) 2008 by Marc S. Ressl (mressl@umich.edu)
 * Released under the GPL
 */

#include "Motherboard.h"

#ifndef TIMINGGENERATOR_H
#define TIMINGGENERATOR_H

#define HORIZ_INIT				0x0
#define HORIZ_HPE				0x40
#define HORIZ_SYNC				0x48
#define HORIZ_SYNC_NUM			4
#define HORIZ_COLORBURST		0x4c
#define HORIZ_COLORBURST_NUM	4
#define HORIZ_ACTIVEVIDEO		0x58
#define HORIZ_END				0x80
#define HORIZ_NUM				(HORIZ_END - HORIZ_HPE + 1)

#define VERT_ACTIVEVIDEO		0x100
#define VERT_MIXED				0x1a0
#define VERT_VBL				0x1c0
#define VERT_SHIRES_END			0x1c8
#define VERT_END				0x200

#define CLOCK14M_CYCLESHORT		14
#define CLOCK14M_CYCLELONG		16
#define CLOCK14M_SCANLINE		((HORIZ_NUM - 1) * CLOCK14M_CYCLESHORT + \
								CLOCK14M_CYCLELONG)

#define NTSC_CLOCK14M			14318180.0
#define NTSC_VERT_START			0xfa
#define NTSC_VERT_NUM			(VERT_END - NTSC_VERT_START)
#define NTSC_FRAMERATE			(NTSC_CLOCK14M / NTSC_VERT_NUM / \
								CLOCK14M_SCANLINE)

#define PAL_CLOCK14M			14250450.0
#define PAL_VERT_START			0xc8
#define PAL_VERT_NUM			(VERT_END - PAL_VERT_START)
#define PAL_FRAMERATE			(PAL_CLOCK14M / PAL_VERT_NUM / \
								CLOCK14M_SCANLINE)

#define APPLEIIGS_ACCELERATIONFACTOR	(2.8 * 0.92 / 1.020)

#define QUARTERSEC_FRAMENUM		0x10

#define VGCINTERRUPT_EXTERNALINTENABLED		(1 << 0)
#define VGCINTERRUPT_SCANLINEINTENABLED		(1 << 1)
#define VGCINTERRUPT_ONESECINTENABLED		(1 << 2)
#define VGCINTERRUPT_EXTERNALINTASSERTED	(1 << 4)
#define VGCINTERRUPT_SCANLINEINTASSERTED	(1 << 5)
#define VGCINTERRUPT_ONESECINTASSERTED		(1 << 6)
#define VGCINTERRUPT_VGCINTASSERTED			(1 << 7)

#define VGCINTERRUPTCLEAR_CLEARSCANLINE		(1 << 5)
#define VGCINTERRUPTCLEAR_CLEARONESEC		(1 << 6)

#define SPEED_SLOT4MOTOR			(1 << 0)
#define SPEED_SLOT5MOTOR			(1 << 1)
#define SPEED_SLOT6MOTOR			(1 << 2)
#define SPEED_SLOT7MOTOR			(1 << 3)
#define SPEED_SHADOWALLBANKS		(1 << 4)
#define SPEED_POWERON				(1 << 6)
#define SPEED_HIGHSPEED				(1 << 7)

class TimingGenerator : public Device {
public:
	TimingGenerator(class Motherboard * motherboard, bool isPalTiming);
	
	void onDevicesConnected();
	void onResetAsserted(bool isRestart);
	
	void setPalTiming(bool value);
	float getFrameRate();
	UINT32 getFrameClockIndex();
	UINT32 getFrameClockNum();
	UINT64 getQ3ClockIndex();
	UINT64 getClockIndex();
	UINT8 readFloatingBus();
	bool isVbl();
	
	void setCpuAccelerationFactor(double value);
	double getCpuAccelerationFactor();
	void enableCpuAcceleration(bool value);
	void assertDisableCpuAcceleration();
	void clearDisableCpuAcceleration();
	void assertDisableCpuAccelerationForOneFrame();
	void clearDisableCpuAccelerationForOneFrame();
	
	void enableVblInterrupt(bool value);
	void clearVblInterrupt();
	bool isVblInterruptEnabled();
	bool isVblInterruptAsserted();
	
	void setVgcInterruptRegister(UINT8 value);
	UINT8 getVgcInterruptRegister();
	void clearVgcInterruptRegister(UINT8 value);
	void setSpeedRegister(UINT8 value);
	UINT8 getSpeedRegister();
	UINT8 getVerticalCountRegister();
	UINT8 getHorizontalCountRegister();
	void enableQuarterSecondInterrupt(bool value);
	void clearQuarterSecondInterrupt();
	bool isQuarterSecondInterruptAsserted();
	
	UINT32 getVerticalCount();
	UINT32 getHorizontalCount();
	UINT32 getScanlineIndex();
	
	void processFrame();
	
private:
	class CPU * cpu;
	class VideoRenderer * videoRenderer;
	
	class Interrupt * externalInterrupt;
	class Interrupt * oneSecondInterrupt;
	class Interrupt * quarterSecondInterrupt;
	class Interrupt * vblInterrupt;
	class Interrupt * scanlineInterrupt;
	
	UINT32 oneSecondInterruptFrameIndex;
	UINT32 oneSecondInterruptFrameNum;
	UINT32 quarterSecondInterruptFrameIndex;
	
	bool isPalTiming;
	double cpuAccelerationFactor;
	bool isCpuAccelerationEnabled;
	UINT32 cpuAccelerationDisableAssertedCount;
	UINT32 cpuAccelerationDisableForOneFrameCount;
	UINT32 frameClockIndex;
	UINT64 clockIndex;
	UINT64 q3ClockIndex;
	
	UINT8 vgcInterruptRegister;
	UINT8 speedRegister;
	
	UINT32 verticalCountStart;
	UINT32 verticalCountIndex;
	
	UINT32 scanlineIndexFromVerticalCount[VERT_END];
	
	void updateCpuAcceleration();
	void onNextFrame();
	void initScanlineIndexFromVerticalCount();
};

#endif
